package ldh.common.testui.controller;

import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import ldh.common.testui.component.CodeTextArea;
import ldh.common.testui.component.HttpCookieControl;
import ldh.common.testui.constant.HttpMethod;
import ldh.common.testui.component.HttpBodyControl;
import ldh.common.testui.component.HttpParamControl;
import ldh.common.testui.constant.ParamType;
import ldh.common.testui.dao.*;
import ldh.common.testui.handle.RunTreeItem;
import ldh.common.testui.handle.TreeContext;
import ldh.common.testui.model.*;
import ldh.common.testui.util.*;

import java.net.URL;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by ldh123 on 2017/6/5.
 */
public class TestFormController extends BaseController implements Initializable{

    @FXML private ChoiceBox<HttpMethod> methodChoiceBox;
    @FXML private TextField urlTextField;

    @FXML private HttpParamControl headerControl;
    @FXML private HttpParamControl paramControl;
    @FXML private HttpCookieControl cookieControl;
    @FXML private HttpBodyControl bodyControl;
//    @FXML private CodeTextArea testHttpResultTextArea;
    @FXML private TextArea testHttpResultTextArea;
    @FXML private Tab bodyTab;
    @FXML private TabPane paramTabPane;
    @FXML private Button runBtn;

    private InvalidationListener urlInvalidationListener = buildUrlInvalidationListener();

    private TestHttp testHttp = null;

    private boolean urlChange = false;

    public void saveTest(ActionEvent actionEvent) throws SQLException {
        if (testHttp == null) {
            testHttp = new TestHttp();
            testHttp.setTreeNodeId(treeItem.getValue().getId());
        }
        testHttp.setUrl(urlTextField.getText().trim());
        testHttp.setMethod(methodChoiceBox.getSelectionModel().getSelectedItem());
        TestHttpDao.save(testHttp);
        setTestHttpTest(testHttp);
    }

    public void runTest(ActionEvent actionEvent) throws SQLException {
        testHttpResultTextArea.setText("");
        Task<Void> task = new Task() {

            @Override
            protected Void call() throws Exception {
                try {
                    saveTest(new ActionEvent());
                    TestLog testLog = TestLog.buildTestLog(treeItem.getValue().getName(), treeItem.getValue().getTreeNodeType().name());
                    TestLogDao.insert(testLog);
                    Map<String, Object> paramMap = TreeUtil.buildParamMap(treeItem);
                    TreeContext treeContext = new TreeContext(treeItem.getValue());
                    treeContext.addParams(paramMap);
                    RunTreeItem.runTreeItem(treeItem, treeContext, null, (result)->{
                        Platform.runLater(()->{
                            if (result != null) {
                                try {
                                    if (result.startsWith("{") || result.startsWith("[")) {
                                        String json = JsonUtil.parseJson(result);
                                        testHttpResultTextArea.setText(json);
                                    } else {
                                        testHttpResultTextArea.setText(result);
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }, testLog, false);
                    testLog.setRunSuccess(1);
                    TestLogDao.update(testLog);
                    return null;
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
        };
        task.setOnFailed((e)-> runBtn.setDisable(false));
        task.setOnSucceeded(e->runBtn.setDisable(false));
        runBtn.setDisable(true);
        ThreadUtilFactory.getInstance().submit(task);
//        new Thread(task).start();
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        methodChoiceBox.setItems(FXCollections.observableArrayList(Arrays.asList(HttpMethod.values())));
        bodyControl.setTestFormController(this);

        headerControl.setParamType(ParamType.Header);
        paramControl.setParamType(ParamType.Param);

        testHttpResultTextArea.setWrapText(false);
        testHttpResultTextArea.setFocusTraversable(false);

//        paramControl.getData().addListener((InvalidationListener) e->{
//            if (urlChange) {
//                System.out.println("urlchange false!!!!!!!!!!!!");
////                urlChange = false;
//                return;
//            }
//            String params = paramControl.getData().stream().map(testHttpParam -> testHttpParam.getName()+ "=" + testHttpParam.getContent()).collect(Collectors.joining("&"));
//            String url = urlTextField.getText().trim();
//            int index = url.indexOf("?");
//            if (index > 0) {
//                url = url.substring(0, index) + "?" +  params;
//            } else {
//                url = url + "?" + params;
//            }
//            urlTextField.setText(url);
//            urlChange = false;
//        });
    }

    private InvalidationListener buildUrlInvalidationListener() {
        return e->{
            urlChange = true;
            System.out.println("urlchange true!!!!!!!!!!!!");
            String url = urlTextField.getText().trim();
            int index = url.indexOf("?");
            if (index < 0) return;
            String[] ts = url.substring(index+1).split("&");
            List<TestHttpParam> testHttpParams = new ArrayList<>();
            for (String t : ts) {
                String[] ps = t.split("=");
                if (ps.length != 2) return;
                TestHttpParam testHttpParam = new TestHttpParam();
                testHttpParam.setContent(ps[1]);
                testHttpParam.setName(ps[0]);
                testHttpParam.setParamType(ParamType.Param);
                testHttpParams.add(testHttpParam);
            }
            mergeTestHttpParams(testHttpParams, paramControl.getData());
            paramControl.getData().clear();
            paramControl.getData().addAll(testHttpParams);
        };
    }

    private void mergeTestHttpParams(List<TestHttpParam> testHttpParams, ObservableList<TestHttpParam> data) {
        int testId = 0;
        for(TestHttpParam t1 : testHttpParams) {
            for(TestHttpParam t2 : data) {
                testId = t2.getTestHttpId();
                if (t1.getName().equals(t2.getName())) {
                    t1.setId(t2.getId());
                }
            }
        }
        Integer testHttpId = testId;
        testHttpParams.forEach(testHttpParam -> testHttpParam.setTestHttpId(testHttpId));
    }

    public void changeContentType(String contentType) {
        headerControl.changeContentType(contentType);
    }

    @Override
    public void setTreeItem(TreeItem<TreeNode> treeItem) {
        this.treeItem = treeItem;
        bodyControl.setTreeItem(treeItem);
        new Thread(new Task<Void>(){

            @Override
            protected Void call() throws Exception {
                loadData();
                return null;
            }
        }).start();
    }

    private void loadData() {
        try {
            List<TestHttp> testHttpList = TestHttpDao.getByTreeNodeId(treeItem.getValue().getId());
            if (testHttpList.size() < 1) return;
            testHttp = testHttpList.get(0);
            Platform.runLater(()->{
                methodChoiceBox.getSelectionModel().select(testHttp.getMethod());
                urlTextField.setText(testHttp.getUrl());

                setTestHttpTest(testHttp);
            });

            List<TestHttpParam> testHttpParams = TestHttpParamDao.getByTestHttpId(testHttp.getId());
            Platform.runLater(()->{
                for (TestHttpParam testHttpParam : testHttpParams) {
                    if (testHttpParam.getParamType() == ParamType.Header) {
                        headerControl.initData(testHttpParam);
                    } else if (testHttpParam.getParamType() == ParamType.Param) {
                        paramControl.initData(testHttpParam);
                    } else if (testHttpParam.getParamType() == ParamType.Cookie) {
                        cookieControl.initData(testHttpParam);
                    } else {
                        new RuntimeException("not support");
                    }
                }
//                urlTextField.textProperty().addListener(urlInvalidationListener);
            });
            List<TestHttpBody> testHttpBodys = TestHttpBodyDao.getByTestHttpId(testHttp.getId());
            Platform.runLater(()->{
                for (TestHttpBody testHttpBody : testHttpBodys) {
                    bodyControl.initData(testHttpBody);
                }
                if (testHttpBodys.size() > 0) paramTabPane.getSelectionModel().select(bodyTab);
            });
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public void setTestHttpTest(TestHttp testHttp) {
        headerControl.setTestHttp(testHttp);
        paramControl.setTestHttp(testHttp);
        cookieControl.setTestHttp(testHttp);
        bodyControl.setTestHttp(testHttp);
    }
}
